import hashlib
import urllib
from datetime import datetime, timedelta

from django.core.urlresolvers import reverse
from django.conf import settings
from django.db import transaction
from django.shortcuts import render, redirect
from django.views import View
import requests

from .forms import ServerApplicationForm, LoginForm
from .models import ServerApplication, Approval
from .libs import utils


class ServerApplyView(View):
    def get(self, request):
        form = ServerApplicationForm()
        return render(request, 'apply.html', {'form': form})

    @transaction.atomic
    def post(self, request):
        form = ServerApplicationForm(request.POST, request.FILES)
        if form.is_valid():
            new_form = form.save()

            # append the direct approver
            boss_email = form.cleaned_data['approver']
            self.append_boss_approver(boss_email, new_form)

            # append default approver
            self.append_default_approver(new_form)

            # send email
            utils.send_email_to_next_approval(new_form)
            return redirect(reverse('application:apply_success', kwargs={'app_id': new_form.id}))
        else:
            return render(request, 'apply.html', {'form': form})

    def get_boss_info(self, email):
        approvers = utils.get_boss_approver_info()
        approver = approvers.get(email)
        name = approver.get('name')
        respectful_name = approver.get('respectful_name')
        return name, respectful_name

    def append_boss_approver(self, boss_email, application):
        boss_name, boss_resp_name = self.get_boss_info(boss_email)
        application.approval_set.create(approver_name=boss_name,
                                        approver_email=boss_email,
                                        approver_respectful_name=boss_resp_name)

    def append_default_approver(self, application):
        for email, username in dict(settings.DEFAULT_APPROVERS).items():
            application.approval_set.create(approver_name=username,
                                            approver_email=email)


class IndexView(View):
    def get(self, request):
        applications = ServerApplication.objects.all()
        for application in applications:
            application.approval__text = utils.get_approval_text(application)
        resp = render(request, 'index.html', {'applications': applications})

        if not request.COOKIES.get('email'):  # user info cookie not found
            token = request.GET.get('accessToken')
            if token:  # redirect from oa.zhenai.com
                ret, info = self.get_user_info(token)
                if ret:  # success in getting user info from OA
                    user_data = info
                    max_age = None
                    realname = user_data.get('realname')
                    email = user_data.get('email')
                    employee_id = user_data.get('employeeid')
                    resp = redirect(reverse('application:index'))
                    resp.set_cookie('email', email, max_age=max_age)
                    resp.set_cookie('token', token, max_age=max_age)
                    resp.set_cookie('realname', urllib.parse.quote(realname), max_age=max_age)
                    resp.set_cookie('employee_id', str(employee_id), max_age=max_age)
                else:  # failed to get user info from OA
                    resp = redirect('%s?next=%s' % (reverse('application:login'), request.path))
            else:
                # cookie and accessToken not found
                resp = redirect('%s?next=%s' % (reverse('application:login'), request.path))
        else:  # cookie found
            if request.GET.get('accessToken'):
                # don't show the access token param in url
                return redirect(reverse('application:index'))

        return resp

    def get_user_info(self, token):
        url = '%s/user/getUserInfo' % (settings.OA_API_URL)
        d = {
            "accessToken": token
        }

        r = requests.post(url, data=d)
        if not r.ok:
            return False, 'OA server error'
        elif r.json().get('ret') != 0:
            return False, r.json().get('msg')
        else:
            return True, r.json().get('data')


class ApprovalView(View):
    def get(self, request, app_id):
        if not request.COOKIES.get('email'):
            return redirect('%s?next=%s' % (reverse('application:login'), request.path))

        context = self.get_basic_context(app_id, request.COOKIES.get('email'))
        return render(request, 'approval.html', context)

    @transaction.atomic
    def post(self, request, app_id):
        email = request.COOKIES.get('email')
        context = self.get_basic_context(app_id, email)
        if request.method == 'POST':
            if request.POST['result'] == 'agree':
                context['message'] = '审批成功！'
                result = True
            else:
                context['message'] = '审批已经驳回！'
                result = False

            ret, info = self.approval(app_id, email, result)
            if not ret:
                context['message'] = info

            # let the page refresh after submit this post,
            # so that let the browser forget what has been submit
            # (it is not a good solution yet)
            context['refresh'] = True

        return render(request, 'approval.html', context)

    def get_basic_context(self, app_id, email):
        context = {}
        need_approve = False
        applications = ServerApplication.objects.filter(pk=app_id)
        if len(applications) != 1:
            context['message'] = '未找到对应申请记录'
            return context

        application = applications[0]
        application.approval__text = utils.get_approval_text(application)

        # match current user with the next approver
        next_approval = utils.get_next_approval(application)
        if next_approval:
            next_approver_email = next_approval.approver_email
            if next_approver_email == email:
                need_approve = True

        context['application'] = application
        context['need_approve'] = need_approve
        return context

    def approval(self, app_id, email, result):
        application = ServerApplication.objects.filter(pk=app_id)[0]

        # check approver identity
        approval = utils.get_next_approval(application)
        if not approval:
            return False, '该申请已经审批完成！'

        if approval.approver_email != email:
            return False, '抱歉，您不是该申请记录的审批人，不能进行审批操作！'

        # save to database
        approval.result = result
        approval.save()  # saving to database must be in front of sending email

        if result:
            if utils.get_next_approval(application):
                finish = False
            else:
                finish = True

            if finish:
                utils.send_pass_email_to_applicant(application)
            else:
                utils.send_email_to_next_approval(application)  # send notification email to next approver
                utils.send_agree_email_to_applicant(application)
        else:
            utils.send_reject_email_to_applicant(application)

        return True, ''


class ApplySuccessView(View):
    def get(self, request, app_id):
        if not request.COOKIES.get('email'):
            return redirect('%s?next=%s' % (reverse('application:login'), request.path))

        applications = ServerApplication.objects.filter(pk=app_id)
        context = {}
        if len(applications) > 0:
            context['application'] = applications[0]

        return render(request, 'success.html', context)


class LoginView(View):
    def get(self, request):
        form = LoginForm()
        return render(request, 'login.html', {'form': form})

    def post(self, request):
        form = LoginForm(request.POST, request.FILES)
        if form.is_valid():
            username = form.cleaned_data['username']
            pwd = form.cleaned_data['password']
            success, login_info = self.get_user_info(username, pwd)
            if not success:
                form.add_error(None, login_info)
            else:
                user_data = login_info
                path = request.GET.get('next')
                if path:
                    resp = redirect(path)
                else:
                    resp = redirect(reverse('application:index'))

                max_age = None
                remember = form.cleaned_data['remember']
                if remember:
                    max_age = settings.LOGIN_MAX_AGE_DAYS * 24 * 60 * 60

                token = user_data.get('accessToken')
                realname = user_data.get('realname')
                email = user_data.get('email')
                employee_id = user_data.get('employeeid')
                resp.set_cookie('email', email, max_age=max_age)
                resp.set_cookie('token', token, max_age=max_age)
                resp.set_cookie('realname', urllib.parse.quote(realname), max_age=max_age)
                resp.set_cookie('employee_id', str(employee_id), max_age=max_age)
                return resp
        return render(request, 'login.html', {'form': form})

    def get_user_info(self, username, pwd):
        m = hashlib.md5()
        mixed_pwd = pwd + 'ZAOA_LOGIN'
        m.update(mixed_pwd.encode())
        mixed_pwd = m.hexdigest()

        url = '%s/user/login' % (settings.OA_API_URL)
        d = {
            "username": username,
            "password": mixed_pwd
        }

        r = requests.post(url, data=d)
        if not r.ok:
            return False, 'OA server error'
        elif r.json().get('ret') != 0:
            return False, r.json().get('msg')
        else:
            return True, r.json().get('data')


class LogoutView(View):
    def get(self, request):
        resp = redirect(reverse('application:login'))
        resp.delete_cookie('email')
        resp.delete_cookie('token')
        resp.delete_cookie('realname')
        resp.delete_cookie('employee_id')
        return resp


class DetailView(View):
    def get(self, request, app_id):
        if not request.COOKIES.get('email'):
            return redirect('%s?next=%s' % (reverse('application:login'), request.path))

        context = {}
        applications = ServerApplication.objects.filter(pk=app_id)
        if len(applications) != 1:
            context['message'] = '未找到对应申请记录'
            return render(request, 'detail.html', context)

        application = applications[0]
        application.approval__text = utils.get_approval_text(application)
        context['application'] = application

        return render(request, 'detail.html', context)
